package co.mobiwise.library;


import co.mobiwise.utils.Utils;
import com.mobiwise.library.ResourceTable;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by mertsimsek on 14/08/15.
 */
public class InteractivePlayerView extends Component implements Component.DrawTask,
        Component.EstimateSizeListener, Component.TouchEventListener {
    // 宽度和高度
    private float width;
    private float height;

    // 中心的X，Y坐标
    private float mCenterX;
    private float mCenterY;

    //图片角度
    private float mCoverRadius;

    /**
     * Progress toggle radius
     */
    private float mRadiusToggle;

    /**
     * Music current duration
     */
    private int mDurationSecondsCurrent = 78;

    /**
     * empty progress color
     */
    private Color mEmptyProgressColor = Color.GRAY;

    /**
     * loaded progress color
     */
    private Color mLoadedProgressColor = Color.RED;
    /**
     * Music duration
     */
    private int mDurationSecondsMax = 123;//test

    /**
     * Duration text size
     */
    private int sizeDurationText = 180;

    /**
     * Cover image paint
     */
    private Paint mCoverPaint;

    /**
     * Duration paint for duration text
     */
    private Paint mDurationPaint;
    /**
     * Cover bitmap
     */
    private PixelMap mBitmapCover;

    /**
     * This will be used to calculate text width.
     */
    private Rect mRectDuration;

    /**
     * empty progress paint
     */
    private Paint mPaintEmptyProgress;

    /**
     * loaded progress paint
     */
    private Paint mPaintLoadedProgress;

    /**
     * Progress toggle
     */
    private Paint mPaintProgressToggle;


    /**
     * progress rectf
     */
    private RectFloat mProgressRectF = new RectFloat();


    /**
     * Action 1 drawable,paint, bitmap and isSelected values
     */
    private PixelMap drawableSelectedAction1;

    private PixelMap drawableUnselectedAction1;

    private boolean isAction2Selected = false;

    private Region middleActionRegion;

    /**
     * Action 2 drawable,paint, bitmap and isSelected values
     */
    private PixelMap drawableSelectedAction2;

    private PixelMap drawableUnselectedAction2;

    private boolean isAction1Selected = false;

    private Region leftActionRegion;

    /**
     * Action 3 drawable,paint, bitmap and isSelected values
     */
    private PixelMap drawableSelectedAction3;

    private PixelMap drawableUnselectedAction3;

    private boolean isAction3Selected = false;


    private Region rightActionRegion;

    private Paint mActionPaint;

    public void setOnActionClickedListener(OnActionClickedListener onActionClickedListener) {
        this.onActionClickedListener = onActionClickedListener;
    }

    private OnActionClickedListener onActionClickedListener;

    /**
     * Is music playing
     */
    private boolean isPlaying = false;

    /**
     * One Second
     */
    private static final int ONE_SECOND = 1000;


    public InteractivePlayerView(Context context) {
        this(context, null);
        init(context);
    }

    public InteractivePlayerView(Context context, AttrSet attrs) {
        this(context, attrs, "0");
        init(context);
    }

    public InteractivePlayerView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);

        // 获取屏幕的宽高度、中心点坐标，调用onEstimateSize方法
        setEstimateSizeListener(this);
        // 添加绘制任务，调用onDraw方法
        addDrawTask(this);
        // 调用onTouchEvent方法
        setTouchEventListener(this);
    }

    /**
     * Inıtıalizes all paint, drawable, bitmap objects.
     * Object initializations must be defined here because this method
     * is called only once.(If you want smooth view, Stay away from onDraw() :))
     *
     * @param context
     */
    public void init(Context context) {

        initProgress();
    }

    Timer timer = new Timer();

    public void startTimer() {
        if (timer != null) {
            timer = new Timer();
        }
        timer.schedule(
                new TimerTask() {

                    @Override

                    public void run() {
                        updateUI();
                    }
                },

                0, ONE_SECOND);
    }

    public boolean isPlaying() {
        return isPlaying;
    }

    public void start() {
        isPlaying = true;
        startTimer();
        if (imagePlay != null && pause != null) {
            imagePlay.setBackground(pause);
        }
    }

    public void stop() {
        isPlaying = false;
        if (timer != null) {
            timer.cancel();
        }
        if (imagePlay != null && play != null) {
            imagePlay.setBackground(play);
        }
    }

    Image imagePlay;
    PixelMapElement pause = null;
    PixelMapElement play = null;

    public void PlayImage(Image image, PixelMapElement play, PixelMapElement pause) {
        imagePlay = image;
        this.pause = pause;
        this.play = play;
    }


    private void updateUI() {
        if (isPlaying && mDurationSecondsMax > mDurationSecondsCurrent) {
            mDurationSecondsCurrent++;

        } else if (mDurationSecondsCurrent == mDurationSecondsMax) {
            mDurationSecondsCurrent = 0;
            stop();
        }
        getContext().getUITaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                invalidate();
            }
        }, 0);
    }


    public void initCover() {
        mBitmapCover = Utils.createPixelMapByResId(ResourceTable.Media_imagetest, getContext(), (int) width, (int) height).get();
        PixelMapShader mBitmapShader = new PixelMapShader(new PixelMapHolder(mBitmapCover), Shader.TileMode.CLAMP_TILEMODE, Shader.TileMode.CLAMP_TILEMODE);
        mCoverPaint = new Paint();
        mCoverPaint.setAntiAlias(true);
        mCoverPaint.setShader(mBitmapShader, Paint.ShaderType.PIXELMAP_SHADER);
    }

    public void initTimeText() {
        mDurationPaint = new Paint();
        mDurationPaint.setAntiAlias(true);
        mDurationPaint.setColor(Color.WHITE);
        //mDurationPaint.setTypeface(mTypeFaceRobotoThin);
        mDurationPaint.setTextSize(sizeDurationText);
    }

    public void initProgress() {
        mPaintEmptyProgress = new Paint();
        mPaintEmptyProgress.setAntiAlias(true);
        mPaintEmptyProgress.setColor(mEmptyProgressColor);
        mPaintEmptyProgress.setStyle(Paint.Style.STROKE_STYLE);
        mPaintEmptyProgress.setStrokeWidth(10.0f);

        mPaintLoadedProgress = new Paint();
        mPaintLoadedProgress.setAntiAlias(true);
        mPaintLoadedProgress.setColor(mLoadedProgressColor);
        mPaintLoadedProgress.setStyle(Paint.Style.STROKE_STYLE);
        mPaintLoadedProgress.setStrokeWidth(9.0f);

        mPaintProgressToggle = new Paint();
        mPaintProgressToggle.setAntiAlias(true);
        mPaintProgressToggle.setColor(mLoadedProgressColor);
        mPaintProgressToggle.setStyle(Paint.Style.FILL_STYLE);
    }

    public void initAction(int size) {
        /**
         * Action images initialization
         */
        mActionPaint = new Paint();
        mActionPaint.setAntiAlias(true);

        //Action 1
        drawableSelectedAction1 = Utils.createPixelMapByResId(ResourceTable.Media_shuffle_selected, getContext(), size, size).get();
        drawableUnselectedAction1 = Utils.createPixelMapByResId(ResourceTable.Media_shuffle_unselected, getContext(), size, size).get();


        //Action 2
        drawableSelectedAction2 = Utils.createPixelMapByResId(ResourceTable.Media_like_selected, getContext(), size, size).get();
        drawableUnselectedAction2 = Utils.createPixelMapByResId(ResourceTable.Media_like_unselected, getContext(), size, size).get();

        //Action 3
        drawableSelectedAction3 = Utils.createPixelMapByResId(ResourceTable.Media_replay_selected, getContext(), size, size).get();
        drawableUnselectedAction3 = Utils.createPixelMapByResId(ResourceTable.Media_replay_unselected, getContext(), size, size).get();
    }


    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawProgress(canvas);
        drawCover(canvas);
        drawActionImages(canvas);
        drawTimeText(canvas);

    }

    public void drawCover(Canvas canvas) {
        canvas.drawCircle(mCenterX, mCenterY, mCoverRadius, mCoverPaint);
    }

    public void drawTimeText(Canvas canvas) {
        String mDurationText = Utils.secondsToTime(mDurationSecondsCurrent);
        mRectDuration = mDurationPaint.getTextBounds(mDurationText);
        canvas.drawText(mDurationPaint, mDurationText,
                (mCenterX - (mRectDuration.getWidth() / 2.0f)),
                (mCenterY + (mRectDuration.getHeight() / 2.0f)));
    }

    public void drawProgress(Canvas canvas) {
        /**
         * Draw progress
         */
        canvas.drawArc(mProgressRectF, new Arc(0, 360, false), mPaintEmptyProgress);
        canvas.drawArc(mProgressRectF, new Arc(270, calculatePastProgress(), false), mPaintLoadedProgress);
        canvas.drawCircle(
                (float) (mCenterX + ((mCenterX - 20.0f) * Math.cos(Math.toRadians(calculatePastProgress() - 90)))),
                (float) (mCenterY + ((mCenterX - 20.0f) * Math.sin(Math.toRadians(calculatePastProgress() - 90)))),
                mRadiusToggle,
                mPaintProgressToggle);
    }

    public void drawActionImages(Canvas canvas) {
        /**
         * Draw action images
         */
        if (drawableSelectedAction1 != null && drawableUnselectedAction1 != null) {

            canvas.drawPixelMapHolder(new PixelMapHolder(isAction1Selected ? drawableSelectedAction1 : drawableUnselectedAction1),
                    (mCenterX - (5 * (mCenterX / 13.0f))),
                    mCenterY + (mCenterY / 3.0f) - (mCenterY / 13.0f),
                    mActionPaint);
        }

        if (drawableSelectedAction2 != null && drawableUnselectedAction2 != null) {
            canvas.drawPixelMapHolder(
                    new PixelMapHolder(isAction2Selected ? drawableSelectedAction2 : drawableUnselectedAction2),
                    mCenterX - (mCenterX / 13.0f),
                    mCenterY + (mCenterY / 3.0f) - (mCenterY / 13.0f),
                    mActionPaint);
        }

        if (drawableSelectedAction3 != null && drawableUnselectedAction3 != null) {

            canvas.drawPixelMapHolder(new PixelMapHolder(isAction3Selected ? drawableSelectedAction3 : drawableUnselectedAction3),
                    (int) (mCenterX + (3 * (mCenterX / 13.0f))),
                    mCenterY + (mCenterY / 3.0f) - (mCenterY / 13.0f),
                    mActionPaint);
        }
    }

    private int calculatePastProgress() {
        return (360 * mDurationSecondsCurrent) / mDurationSecondsMax;
    }

    public void setMax(int mDurationSecondsMax) {
        this.mDurationSecondsMax = mDurationSecondsMax;
        invalidate();
    }

    @Override
    public boolean onEstimateSize(int i, int i1) {
        int mWidth = EstimateSpec.getSize(i);
        int mHeight = EstimateSpec.getSize(i1);
        width = mWidth;
        height = mHeight;
        initCover();
        int minSide = Math.min(mWidth, mHeight);
        mCenterX = minSide / 2f;
        mCenterY = minSide / 2f;
        sizeDurationText = mHeight / 5;
        middleActionRegion = new Region(new Rect(
                (int) (mCenterX - (mCenterX / 13.0f)),
                (int) (mCenterY + (mCenterY / 3.0f) - (mCenterY / 13.0f)),
                (int) (mCenterX + (mCenterX / 13.0f)),
                (int) (mCenterY + (mCenterY / 3.0f) + (mCenterY / 13.0f))));

        leftActionRegion = new Region(new Rect((int) (mCenterX - (5 * (mCenterX / 13.0f))),
                (int) (mCenterY + (mCenterY / 3.0f) - (mCenterY / 13.0f)),
                (int) (mCenterX - (3 * (mCenterX / 13.0f))),
                (int) (mCenterY + (mCenterY / 3.0f) + (mCenterY / 13.0f)))
        );

        rightActionRegion = new Region(new Rect((int) (mCenterX + (3 * (mCenterX / 13.0f))),
                (int) (mCenterY + (mCenterY / 3.0f) - (mCenterY / 13.0f)),
                (int) (mCenterX + (5 * (mCenterX / 13.0f))),
                (int) (mCenterY + (mCenterY / 3.0f) + (mCenterY / 13.0f))));
        initAction(minSide / 10);
        initTimeText();
        mCoverRadius = minSide / 2.3f;
        mRadiusToggle = mWidth / 40.0f;
        mProgressRectF.modify(20.0f, 20.0f, mWidth - 20.0f, mHeight - 20.0f);
        setEstimatedSize(
                EstimateSpec.getChildSizeWithMode(mWidth, mHeight, EstimateSpec.PRECISE),
                EstimateSpec.getChildSizeWithMode(mWidth, mHeight, EstimateSpec.PRECISE)
        );
        return true;
    }


    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {

        float x = touchEvent.getPointerPosition(touchEvent.getIndex()).getX();
        float y = touchEvent.getPointerPosition(touchEvent.getIndex()).getY();

        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN: {
                return true;
            }
            case TouchEvent.PRIMARY_POINT_UP: {
                if (onActionClickedListener != null) {
                    if (leftActionRegion.contains((int) x, (int) y)) {
                        onActionClickedListener.onActionClicked(1);
                        isAction1Selected = !isAction1Selected;
                        invalidate();
                    } else if (middleActionRegion.contains((int) x, (int) y)) {
                        onActionClickedListener.onActionClicked(2);
                        isAction2Selected = !isAction2Selected;
                        invalidate();
                    } else if (rightActionRegion.contains((int) x, (int) y)) {
                        onActionClickedListener.onActionClicked(3);
                        isAction3Selected = !isAction3Selected;
                        invalidate();
                    }
                }
            }
            break;
        }

        return true;

    }
}
